﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Xml;
using Higgs.Web.AtomPub.Models;

namespace Higgs.Web.AtomPub.Binders
{
    public class EntryModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var request = controllerContext.RequestContext.HttpContext.Request;
            IEnumerator enumerator = null;
            var reader = new StreamReader(request.InputStream, Encoding.UTF8);
            var s = reader.ReadToEnd();
            reader.Close();
            var txtReader = new StringReader(s);
            var document = new XmlDocument();
            document.Load(txtReader);
            var documentElement = document.DocumentElement;
            if (ResolveElementName(documentElement) != "atom:entry")
            {
                throw new Exception("atom:entry not found at XML root");
            }

            var entry = DependencyResolver.Current.GetService<IEntry>();
            var list = new List<string>();

            try
            {
                enumerator = documentElement.ChildNodes.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    var current = (XmlNode) enumerator.Current;
                    if (current.NodeType != XmlNodeType.Element)
                    {
                        continue;
                    }
                    var element2 = (XmlElement) current;
                    var str2 = ResolveElementName(current);
                    if (str2 == "atom:title")
                    {
                        entry.Title = element2.InnerText;
                    }
                    else
                    {
                        switch (str2)
                        {
                            case "atom:published":
                                entry.PublishedDate = XmlConvert.ToDateTime(element2.InnerText, XmlDateTimeSerializationMode.Local);
                                break;

                            case "atom:category":
                                list.Add(element2.GetAttribute("term"));
                                break;

                            case "app:control":
                                IEnumerator enumerator2 = null;
                                try
                                {
                                    enumerator2 = current.ChildNodes.GetEnumerator();
                                    while (enumerator2.MoveNext())
                                    {
                                        var node2 = (XmlNode) enumerator2.Current;
                                        if ((node2.NodeType == XmlNodeType.Element) && (ResolveElementName(node2) == "app:draft"))
                                        {
                                            if ((node2).InnerText == "yes")
                                            {
                                                entry.Draft = true;
                                            }
                                            break;
                                        }
                                    }
                                }
                                finally
                                {
                                    if (enumerator2 is IDisposable)((IDisposable)enumerator2).Dispose();
                                }
                                break;

                            case "atom:content":
                                switch (element2.GetAttribute("type"))
                                {
                                    case null:
                                    case "":
                                    case "text":
                                        entry.ContentHtml = HttpUtility.HtmlEncode(element2.InnerText);
                                        break;
                                    case "html":
                                        entry.ContentHtml = element2.InnerText;
                                        break;
                                    case "xhtml":
                                        entry.ContentHtml = element2.InnerXml;
                                        break;
                                    default: throw new Exception("Content type not supported");
                                }
                                break;
                        }
                    }
                }
            }
            finally
            {
                if (enumerator is IDisposable)
                {
                    (enumerator as IDisposable).Dispose();
                }
            }
            entry.Terms = list.ToArray();

            return entry;
        }

        private static string ResolveElementName(XmlNode el)
        {
            switch (el.NamespaceURI.ToLower())
            {
                case "http://www.w3.org/2005/atom":
                    return ("atom:" + el.LocalName);

                case "http://www.w3.org/2007/app":
                    return ("app:" + el.LocalName);
            }
            return "????";
        }
    }
}
